package playnsimple.core.state;

import static playn.core.PlayN.graphics;

import org.jbox2d.common.Vec2;

import playn.core.Image;
import playn.core.ImageLayer;
import playn.core.PlayN;
import playn.core.Pointer;
import playnsimple.core.PlaynSimple;


public class PlayState extends BaseState {
    
    private ImageLayer largeImageLayer;
    private Vec2 largeImagePos;
    private Vec2 touchPos;
    private float imageOverlapX;
    private float imageOverlapY;

    public PlayState(String label) {
        super(label);
    }
    
    @Override
    public void enter() {
        Image largeImage = PlayN.assets().getImage("images/botticelli.jpg");
        largeImageLayer = PlayN.graphics().createImageLayer(largeImage);
        largeImagePos = new Vec2(0,0);
        
        imageOverlapX = (largeImageLayer.width() - PlayN.graphics().width()) * .5f;
        imageOverlapY = (largeImageLayer.height() - PlayN.graphics().height()) * .5f;
        PlaynSimple.log("(Min/Max X, Min/Max Y): " + imageOverlapX + "," + imageOverlapY);
        
        addListeners();
    }

    @Override
    public void update() {
        // contain image within screen
        largeImagePos = containImageLayer(largeImageLayer, largeImagePos);
        
        // translate image position
        Vec2 imageSize = new Vec2(largeImageLayer.width(), largeImageLayer.height());
        Vec2 translatedPt = worldToScreen(largeImagePos, imageSize);
        largeImageLayer.setTranslation(translatedPt.x, translatedPt.y);
        
        // if pulled to lower left edge, game over
        Boolean atRightEdge = largeImagePos.x == -imageOverlapX;
        Boolean atBottomEdge = largeImagePos.y == imageOverlapY;
        //PlaynSimple.log(translatedPt.y == -PlaynSimple.windowSize.y);
        if (atRightEdge && atBottomEdge) {
            machine.changeState("end");
        }
    }
    
    @Override
    public void paint() {
        PlayN.graphics().rootLayer().add(largeImageLayer);
    }

    private Vec2 containImageLayer(ImageLayer imageLayer,
            Vec2 imagePos) {
        float newX, newY;
        newX = Math.max(imagePos.x, imageOverlapX * -1f);
        newX = Math.min(newX, imageOverlapX);
        newY = Math.max(imagePos.y, imageOverlapY * -1f);
        newY = Math.min(newY, imageOverlapY);
        return new Vec2(newX, newY);
    }

    /*
     * Additional Methods
     */
    private void addListeners() {         
        largeImageLayer.addListener(new Pointer.Listener() {
            private Vec2 imagePosAtTouch;
            
            @Override
            public void onPointerStart(Pointer.Event event) {
                PlaynSimple.log("Pointer start: " + event);
                touchPos = screenToWorld(new Vec2(event.x(), event.y()));
                imagePosAtTouch = largeImagePos;
            }
            
            @Override
            public void onPointerEnd(Pointer.Event event) {
                PlaynSimple.log("Pointer end: " + event);
            }

            @Override
            public void onPointerDrag(Pointer.Event event) {
                Vec2 pointPos = screenToWorld(new Vec2(event.x(), event.y()));
                Vec2 delta = touchPos.sub(pointPos);
                Vec2 grabDelta = delta.mul(-1f);
                largeImagePos = imagePosAtTouch.add(grabDelta);
            }
        });               
    }
    
    private Vec2 worldToScreen(Vec2 pt) {
        return new Vec2(worldToScreenX(pt.x), worldToScreenY(pt.y));
    }
    
    private Vec2 worldToScreen(Vec2 pt, Vec2 dim) {
        Vec2 offset = new Vec2(dim.mul(0.5f));
        Vec2 translatedPt = new Vec2(worldToScreenX(pt.x), worldToScreenY(pt.y));
        return translatedPt.sub(offset);
    }

    private float worldToScreenX(Number x) {
        Vec2 screenCenter = getDisplayCenter();
        return screenCenter.x + x.floatValue();
    }

    private float worldToScreenY(Number y) {
        Vec2 screenCenter = getDisplayCenter();
        return screenCenter.y - y.floatValue();
    }
    
    private Vec2 screenToWorld(Vec2 pt) {
        return new Vec2(screenToWorldX(pt.x), screenToWorldY(pt.y));
    }
    
    private float screenToWorldX(Number x) {
        Vec2 screenCenter = getDisplayCenter();
        return x.floatValue() - screenCenter.x;
    }

    private float screenToWorldY(Number y) {
        Vec2 screenCenter = getDisplayCenter();
        return screenCenter.y - y.floatValue();
    }
    
    
    private Vec2 getDisplayCenter() {
        Vec2 displaySize = new Vec2(graphics().width(), graphics().height());
        return new Vec2(displaySize.mul(0.5f));
    }

}
